package com.jse.api;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.jse.Http;
import com.jse.Times;
import com.jse.json.JsonObject;

/**
 * 用于生成阿里云短信服务API请求的工具类。
 * 
 * 此类提供了一个静态方法 `api` 用于构建短信发送、批量短信发送及查询发送记录的API请求URL。
 * 
 * @author dzh
 */
public class Sms {

	/**
	 * 生成阿里云短信服务API请求的URL。
	 * 
	 * @param params 请求参数，必须包含：
	 *             <ul>
	 *                 <li>AccessKeyId (String): 用户的Access Key ID。</li>
	 *                 <li>AccessSecret (String): 用户的Access Secret。</li>
	 *                 <li>Action (String): 操作类型，如 "SendSms", "SendBatchSms", 或 "QuerySendDetails"。</li>
	 *                 <li>以及其他根据操作类型所需的参数：</li>
	 *                 <ul>
	 *                     <li>如果 Action 为 "SendSms"，则还需要包含：
	 *                         <ul>
	 *                             <li>PhoneNumbers (String): 接收短信的手机号码。</li>
	 *                             <li>SignName (String): 短信签名。</li>
	 *                             <li>TemplateParam (String): 模板参数JSON格式。</li>
	 *                             <li>TemplateCode (String): 短信模板编号。</li>
	 *                             <li>OutId (String, 可选): 外部流水扩展字段。</li>
	 *                         </ul>
	 *                     </li>
	 *                     <li>如果 Action 为 "SendBatchSms"，则还需要包含：
	 *                         <ul>
	 *                             <li>PhoneNumberJson (String): 批量发送短信的手机号码JSON数组。</li>
	 *                             <li>SignNameJson (String, 可选): 短信签名JSON数组。</li>
	 *                             <li>TemplateParamJson (String, 可选): 模板参数JSON数组。</li>
	 *                             <li>TemplateCode (String): 短信模板编号。</li>
	 *                             <li>SmsUpExtendCodeJson (String, 可选): 上行短信扩展码JSON数组。</li>
	 *                         </ul>
	 *                     </li>
	 *                     <li>如果 Action 为 "QuerySendDetails"，则还需要包含：
	 *                         <ul>
	 *                             <li>SendDate (String): 发送日期，格式为yyyyMMdd。</li>
	 *                             <li>PhoneNumber (String): 用于查询的手机号码。</li>
	 *                             <li>CurrentPage (String): 当前页数。</li>
	 *                             <li>PageSize (String): 每页大小。</li>
	 *                             <li>BizId (String, 可选): 业务流水ID，用于精确查询。</li>
	 *                         </ul>
	 *                     </li>
	 *                 </ul>
	 * @return 生成的API请求URL。
	 */
    public static String api(Map params) {
		String action="http://dysmsapi.aliyuncs.com/?Signature=";
		String accessSecret = params.remove("AccessSecret").toString();
		java.text.SimpleDateFormat df = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));// 这里一定要设置GMT时区
		java.util.Map<String, String> paras = new java.util.HashMap<String, String>();
		paras.put("SignatureMethod", "HMAC-SHA1");
		paras.put("SignatureNonce", java.util.UUID.randomUUID().toString());
		paras.put("SignatureVersion", "1.0");
		paras.put("Timestamp", df.format(new java.util.Date()));
		paras.put("Format", "json");
		paras.put("Version", "2017-05-25");
		paras.put("RegionId", "cn-hangzhou");
		paras.putAll(params);
		if (paras.containsKey("Signature"))
			paras.remove("Signature");
		java.util.TreeMap<String, String> sortParas = new java.util.TreeMap<String, String>();
		sortParas.putAll(paras);
		
		java.util.Iterator<String> it = sortParas.keySet().iterator();
		StringBuilder sortQueryStringTmp = new StringBuilder();
		while (it.hasNext()) {
		    String key = it.next();
		    sortQueryStringTmp.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(paras.get(key)));
		}
		String sortedQueryString = sortQueryStringTmp.substring(1);// 去除第一个多余的&符号
		StringBuilder stringToSign = new StringBuilder();
		stringToSign.append("GET").append("&");
		stringToSign.append(specialUrlEncode("/")).append("&");
		stringToSign.append(specialUrlEncode(sortedQueryString));
		String sign = sign(accessSecret + "&", stringToSign.toString());
		String Signature = specialUrlEncode(sign);//
		return action+Signature+"&"+sortedQueryString;
	}
	
	public static String sign(String accessSecret, String stringToSign) {
	    try {
	    	javax.crypto.Mac mac = javax.crypto.Mac.getInstance("HmacSHA1");
		    mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes("UTF-8"), "HmacSHA1"));
		    byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
	    	return Base64.getEncoder().encodeToString(signData);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	    
	}
	
	public static String specialUrlEncode(String value) {
	    try {
			String key= java.net.URLEncoder.encode(value, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
			return key;
	    } catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}
}